package com.cynteka.cyfoman.core;

import com.cynteka.cyfoman.core.config.*;
import org.apache.commons.io.FileUtils;

import javax.sql.DataSource;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: ukman
 * Date: 15.07.2011
 * Time: 10:30:08
 */
public class ActionProcessor {

    private static Logger logger = Logger.getLogger(ActionProcessor.class.getName());

    public static void processAction(ActionMD actionMD, ValueObject valueObject, File baseFolder, DataSource ds, File[] filesToCopy) {
        // valueObject.firePrepareToBeStored();
        processTable(actionMD, valueObject, baseFolder, ds, filesToCopy);
        processFolders(actionMD, valueObject, baseFolder, ds, filesToCopy);

    }

    public static void processFolders(ActionMD actionMD, ValueObject valueObject, File baseFolder, DataSource ds, File[] filesToCopy) {
        File lastDir = null;
        for (String folderName : actionMD.getFolders()) {

            folderName = Util.substituteParams(folderName, valueObject);
            folderName = folderName.trim();

            File newFolder = new File(baseFolder, folderName);
            if (!newFolder.exists()) {
                newFolder.mkdirs();
            } else {
                logger.log(Level.WARNING, "Folder exists : " + newFolder);
            }
            lastDir = newFolder;
        }

        if (lastDir != null && filesToCopy != null) {
            for (File f : filesToCopy) {
                File newFile = new File(lastDir, f.getName());
                if (f.isFile()) {
                    try {
                        FileUtils.moveFile(f, newFile);
                    } catch (IOException e) {
                        logger.log(Level.SEVERE, "Can not move file " + f + " to " + newFile, e);
                        JOptionPane.showMessageDialog(null, "Не могу скопировать файл\n" + f + "\nв\n" + newFile, "Ошибка", JOptionPane.ERROR_MESSAGE);
                    }
                } else if (f.isDirectory()) {
                    try {
                        FileUtils.moveDirectory(f, newFile);
                    } catch (IOException e) {
                        logger.log(Level.SEVERE, "Can not move folder " + f + " to " + newFile, e);
                        JOptionPane.showMessageDialog(null, "Не могу скопировать папку\n" + f + "\nв\n" + newFile, "Ошибка", JOptionPane.ERROR_MESSAGE);
                    }
                }
            }
        }
    }

    public static void processTable(ActionMD actionMD, ValueObject valueObject, File baseFolder, DataSource ds, File[] filesToCopy) {
        if (actionMD.getTable() != null && !"".equals(actionMD.getTable())) {
            Connection connection = null;
            String query = null;
            try {
                connection = ds.getConnection();

                if (valueObject.getId() == null) {
                    query = Util.generateInsertQuery(actionMD);
                } else {

                    query = Util.generateUpdateQuery(actionMD);
                }

                connection.setAutoCommit(false);

                PreparedStatement statement = connection.prepareStatement(query);
                int idx = 1;
                for (ParamMD param : actionMD.getActionParams()) {
                    Object value = valueObject.getParam(param);
                    if (value instanceof RefItem) {
                        RefItem refItem = (RefItem) value;
                        value = refItem.id;
                    }
                    if (param.getParamType() == ParamType.COLLECTION) {
                        // process another table
                        break;
                    }
                    statement.setObject(idx, value);
                    idx++;
                }
                if (valueObject.getId() != null) {
                    statement.setObject(idx, valueObject.getId());
                    idx++;
                }
                statement.execute();

                if (valueObject.getId() == null) {

                    statement = connection.prepareStatement("select last_insert_id()");
                    ResultSet rs = statement.executeQuery();
                    rs.next();
                    int id = rs.getInt(1);
                    valueObject.setId(id);
                }


                for (ParamMD param : actionMD.getActionParams()) {
                    if (param.getParamType() == ParamType.COLLECTION) {
                        // Collections
                        // clear previous
                        CollectionMD collectionMD = param.getCollection();
                        query = String.format("delete from %1s where %2s = ?", collectionMD.getCrossTable(), collectionMD.getReferenceFromField());
                        statement = connection.prepareStatement(query);
                        statement.setObject(1, valueObject.getId());
                        statement.execute();

                        query = String.format("insert into %1s (%2s, %3s) values(?,?)", collectionMD.getCrossTable(), collectionMD.getReferenceFromField(), collectionMD.getReferenceToField());
                        statement = connection.prepareStatement(query);

                        Collection<RefItem> refItems = (Collection<RefItem>) valueObject.getParam(param);
                        for (RefItem refItem : refItems) {
                            statement.setObject(1, valueObject.getId());
                            statement.setObject(2, refItem.id);
                            statement.execute();
                        }
                    }
                }

                connection.commit();
            } catch (SQLException e) {
                logger.log(Level.SEVERE, "Can not execute statement " + query, e);
                try {
                    connection.rollback();
                } catch (SQLException e1) {
                    logger.log(Level.SEVERE, "Can not rollback transaction " + query, e);
                }
            } finally {
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        logger.log(Level.SEVERE, "Can not close connection", e);
                    }
                }
            }

        }

    }
}
